package view.helper;

import java.util.HashMap;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;

import org.zkoss.zk.ui.Component;

import view.component.CardComponent;
import view.component.EndCellComponent;
import view.component.FreeCellComponent;
import view.component.PileComponent;

import model.Card;
import model.Game;
import model.Pile;

public class Adaptor implements Observer {
	
	Game game;	
	Pile[] realPiles;
	Game.Cell[] realCells;
	
	FreeCellComponent[] freecells;
	EndCellComponent[] endcells;
	PileComponent[] piles;
	
	Map<Object, CardHolder> holders = new HashMap<Object, CardHolder>();
	Map<Object, CardComponent> cards = new HashMap<Object, CardComponent>();
	
	public Adaptor() {
		game = new Game();
		game.addObserver(this);
		linkModel();
	}	
	
	private void linkModel() {
		linkFreeCells();
		linkEndCells();
		linkPiles();
	}	

	
	public void linkFreeCells() {
		realCells = Game.Cell.values();
		freecells = new FreeCellComponent[realCells.length];
		for (int j=0; j<freecells.length; j++) {
			FreeCellComponent freecell = new FreeCellComponent();
			freecell.setAdaptor(this);
			freecells[j]=freecell;
			holders.put(realCells[j], freecell);
		}
	}
	
	public void linkEndCells() {
		Card.Suit figures[] = {Card.Suit.Spade, Card.Suit.Diamond, Card.Suit.Heart, Card.Suit.Club};		
		endcells = new EndCellComponent[4];
		for (int j=0; j<freecells.length; j++) {
			EndCellComponent endcell = new EndCellComponent(figures[j].toString());
			endcell.setAdaptor(this);
			endcells[j] = endcell;
			holders.put(figures[j], endcell);
		}
	}
	
	private void linkPiles() {
		realPiles = game.getPiles();
		piles = new PileComponent[realPiles.length];		
		for (int i=0; i<realPiles.length; i++) {
			piles[i] = new PileComponent();
			piles[i].setAdaptor(this);
			holders.put(realPiles[i], piles[i]);
			for (int j=0; j<realPiles[i].toArray().length; j++) {
				Card oldCard = (Card) realPiles[i].toArray()[j];
				CardComponent card = new CardComponent(oldCard.toString());
				card.setAdaptor(this);
				piles[i].pushCard(card);
				cards.put(oldCard, card);
			}
		}
	}

	
	public FreeCellComponent[] getFreeCells() {
		return freecells;
	}
	
	public EndCellComponent[] getEndCells() {
		return endcells;
	}
	
	public PileComponent[] getPiles() {
		return piles;
	}		
	
	public void onFreeCellComponentDropFromPileComponent(CardComponent dragged, FreeCellComponent target) {		
		//back-end model actions	
		try {
			System.out.println("onFreeCellDropFromPile()...");
			Pile srcPile = (Pile)getHolderKeyObject(dragged.getTopHolder());
			Game.Cell dstFreeCell = (Game.Cell)getHolderKeyObject(target);			
			game.moveFromPile(srcPile.getPileId(), dragged.getQueueCount());
			game.moveToFreeCell(dstFreeCell);		
		} catch (Exception e) {
		e.printStackTrace();
		}	
	}
		
	public void onEndCellComponentDropFromFreeCellComponent(CardComponent dragged, EndCellComponent target) {		
		//back-end model actions
		try {
			System.out.println("onEndCellDropFromFreeCell()...");
			Game.Cell srcFreeCell = (Game.Cell)getHolderKeyObject(dragged.getTopHolder());
			//Card.Suit dstEndCell = (Card.Suit)getHolderKeyObject(target);						
			game.moveFromFreeCell(srcFreeCell);			
			game.moveToPlayedCards();		
		} catch (Exception e) {
		e.printStackTrace();
		}
	}
	
	public void onEndCellComponentDropFromPileComponent(CardComponent dragged, EndCellComponent target) {		
		//back-end model actions
		try {
			System.out.println("onEndCellDropFromPile()...");
			Pile srcPile = (Pile)getHolderKeyObject(dragged.getTopHolder());
			game.moveFromPile(srcPile.getPileId(), dragged.getQueueCount());
			game.moveToPlayedCards();
		} catch (Exception e) {
		e.printStackTrace();
		}
	}
	
	public void onPileComponentDropFromFreeCellComponent(CardComponent dragged, PileComponent target) {		
		//back-end model actions
		try {
			System.out.println("# onPileDropFromFreeCell()...");
			Game.Cell srcFreeCell = (Game.Cell)getHolderKeyObject(dragged.getTopHolder());
			Pile dstPile = (Pile)getHolderKeyObject(target);						
			game.moveFromFreeCell(srcFreeCell);
			game.moveToPile(dstPile.getPileId());		
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void onPileComponentDropFromPileComponent(CardComponent dragged, PileComponent target) {		
		//back-end model actions
		try {
			System.out.println("# onPileDropFromPile()...");
			Pile srcPile = (Pile)getHolderKeyObject(dragged.getTopHolder());
			Pile dstPile = (Pile)getHolderKeyObject(target);			
			game.moveFromPile(srcPile.getPileId(), dragged.getQueueCount());
			game.moveToPile(dstPile.getPileId());			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	private Object getHolderKeyObject (CardHolder target) throws Exception {
		for (Object object: holders.keySet()) {
			if (holders.get(object).equals(target)) {
				return object;
			}			
		}
		throw new Exception("Problem finding the key in holders map");
	}
	
	public void show(Component parent) {
		for (Object object: holders.keySet()) {
			holders.get(object).setParent(parent);			
		}
	}

	public void update(Observable o, Object arg) {
		System.out.println("@update-model ---");		
		Object draggedKey = ((Object[])arg)[0]; 
		Object targetKey = ((Object[])arg)[1];
		CardComponent dragged = cards.get(draggedKey);
		CardHolder target = holders.get(targetKey);
		System.out.println(target);
		target.pushCard(dragged);
		System.out.println(game);
	}

}
